"""
负载测试工具类
提供摄像头模拟、性能监控和测试报告生成功能
"""
import asyncio
import time
import random
import numpy as np
from typing import List, Dict, Any, Optional, Callable, Tuple
from datetime import datetime, timedelta
import logging
import json
from dataclasses import dataclass, asdict
from collections import defaultdict, deque
import psutil

logger = logging.getLogger(__name__)


@dataclass
class LoadTestConfig:
    """负载测试配置"""
    max_cameras: int = 500
    test_duration: int = 300  # 5分钟
    ramp_up_time: int = 60    # 1分钟逐步增加负载
    ai_algorithms_per_camera: int = 2
    target_fps: float = 3.0
    error_threshold: float = 0.05  # 5%错误率阈值
    cpu_threshold: float = 90.0
    memory_threshold: float = 85.0
    gpu_threshold: float = 95.0


@dataclass
class PerformanceSnapshot:
    """性能快照"""
    timestamp: datetime
    active_cameras: int
    cpu_percent: float
    memory_percent: float
    gpu_utilization: float
    processing_fps: float
    error_rate: float
    latency_ms: float
    throughput: float


class CameraSimulator:
    """摄像头模拟器"""
    
    def __init__(self, camera_id: str, config: Dict[str, Any] = None):
        self.camera_id = camera_id
        self.config = config or {}
        self.is_active = False
        self.frames_generated = 0
        self.errors_count = 0
        self.start_time: Optional[datetime] = None
        self.last_frame_time: Optional[datetime] = None
        
        # 配置参数
        self.fps = self.config.get("fps", 3.0)
        self.error_rate = self.config.get("error_rate", 0.01)
        self.frame_size = self.config.get("frame_size", (480, 640, 3))
        self.ai_algorithms = self.config.get("ai_algorithms", ["behavior_analysis"])
        
        # 性能统计
        self.frame_generation_times = deque(maxlen=100)
        
    async def start(self):
        """启动摄像头模拟"""
        self.is_active = True
        self.start_time = datetime.now()
        logger.debug(f"摄像头 {self.camera_id} 启动")
        
    async def stop(self):
        """停止摄像头模拟"""
        self.is_active = False
        logger.debug(f"摄像头 {self.camera_id} 停止")
        
    async def generate_frame(self) -> Optional[np.ndarray]:
        """生成视频帧"""
        if not self.is_active:
            return None
            
        start_time = time.time()
        
        # 模拟错误
        if random.random() < self.error_rate:
            self.errors_count += 1
            raise Exception(f"摄像头 {self.camera_id} 帧生成错误")
        
        # 生成随机帧数据
        frame = np.random.randint(0, 255, self.frame_size, dtype=np.uint8)
        
        # 更新统计
        self.frames_generated += 1
        self.last_frame_time = datetime.now()
        
        generation_time = time.time() - start_time
        self.frame_generation_times.append(generation_time)
        
        return frame
    
    def get_statistics(self) -> Dict[str, Any]:
        """获取摄像头统计信息"""
        uptime = 0
        if self.start_time:
            uptime = (datetime.now() - self.start_time).total_seconds()
            
        avg_generation_time = 0
        if self.frame_generation_times:
            avg_generation_time = sum(self.frame_generation_times) / len(self.frame_generation_times)
            
        return {
            "camera_id": self.camera_id,
            "is_active": self.is_active,
            "uptime_seconds": uptime,
            "frames_generated": self.frames_generated,
            "errors_count": self.errors_count,
            "error_rate": self.errors_count / max(1, self.frames_generated),
            "avg_generation_time_ms": avg_generation_time * 1000,
            "last_frame_time": self.last_frame_time.isoformat() if self.last_frame_time else None
        }


class LoadTestOrchestrator:
    """负载测试编排器"""
    
    def __init__(self, config: LoadTestConfig):
        self.config = config
        self.cameras: Dict[str, CameraSimulator] = {}
        self.performance_snapshots: List[PerformanceSnapshot] = []
        self.test_start_time: Optional[datetime] = None
        self.test_end_time: Optional[datetime] = None
        
        # 性能监控
        self.monitoring_task: Optional[asyncio.Task] = None
        self.is_monitoring = False
        
    async def setup_cameras(self) -> List[CameraSimulator]:
        """设置摄像头模拟器"""
        logger.info(f"设置 {self.config.max_cameras} 个摄像头模拟器")
        
        ai_algorithm_sets = [
            ["behavior_analysis", "crowd_density"],
            ["waste_detection", "cleanliness_assessment"],
            ["teaching_quality", "classroom_quality"],
            ["conflict_detection", "pose_detection"],
            ["lighting_detection", "energy_analysis"]
        ]
        
        cameras = []
        for i in range(self.config.max_cameras):
            camera_id = f"load_test_camera_{i+1:03d}"
            
            # 随机选择AI算法组合
            ai_algorithms = random.choice(ai_algorithm_sets)
            if len(ai_algorithms) > self.config.ai_algorithms_per_camera:
                ai_algorithms = ai_algorithms[:self.config.ai_algorithms_per_camera]
            
            camera_config = {
                "fps": self.config.target_fps,
                "error_rate": random.uniform(0.005, 0.02),  # 0.5%-2%错误率
                "ai_algorithms": ai_algorithms,
                "priority": random.randint(1, 10)
            }
            
            camera = CameraSimulator(camera_id, camera_config)
            cameras.append(camera)
            self.cameras[camera_id] = camera
            
        logger.info(f"成功设置 {len(cameras)} 个摄像头模拟器")
        return cameras
    
    async def start_performance_monitoring(self):
        """启动性能监控"""
        self.is_monitoring = True
        self.monitoring_task = asyncio.create_task(self._monitor_performance())
        logger.info("性能监控已启动")
        
    async def stop_performance_monitoring(self):
        """停止性能监控"""
        self.is_monitoring = False
        if self.monitoring_task:
            self.monitoring_task.cancel()
            try:
                await self.monitoring_task
            except asyncio.CancelledError:
                pass
        logger.info("性能监控已停止")
        
    async def _monitor_performance(self):
        """性能监控循环"""
        while self.is_monitoring:
            try:
                # 收集系统性能指标
                cpu_percent = psutil.cpu_percent(interval=1)
                memory_info = psutil.virtual_memory()
                
                # 模拟GPU使用率（实际应该从GPU监控获取）
                active_cameras = sum(1 for cam in self.cameras.values() if cam.is_active)
                gpu_utilization = min(95.0, active_cameras * 0.18)
                
                # 计算处理性能指标
                total_frames = sum(cam.frames_generated for cam in self.cameras.values())
                total_errors = sum(cam.errors_count for cam in self.cameras.values())
                error_rate = total_errors / max(1, total_frames)
                
                # 计算平均延迟和吞吐量
                avg_latency = self._calculate_average_latency()
                throughput = self._calculate_throughput()
                
                # 创建性能快照
                snapshot = PerformanceSnapshot(
                    timestamp=datetime.now(),
                    active_cameras=active_cameras,
                    cpu_percent=cpu_percent,
                    memory_percent=memory_info.percent,
                    gpu_utilization=gpu_utilization,
                    processing_fps=self.config.target_fps,
                    error_rate=error_rate,
                    latency_ms=avg_latency,
                    throughput=throughput
                )
                
                self.performance_snapshots.append(snapshot)
                
                # 记录性能日志
                if len(self.performance_snapshots) % 10 == 0:  # 每10次记录一次
                    logger.info(f"性能监控: 活跃摄像头 {active_cameras}, "
                               f"CPU {cpu_percent:.1f}%, 内存 {memory_info.percent:.1f}%, "
                               f"GPU {gpu_utilization:.1f}%, 错误率 {error_rate:.3f}")
                
                await asyncio.sleep(5)  # 每5秒监控一次
                
            except Exception as e:
                logger.error(f"性能监控错误: {e}")
                await asyncio.sleep(1)
    
    def _calculate_average_latency(self) -> float:
        """计算平均延迟"""
        all_generation_times = []
        for camera in self.cameras.values():
            if camera.frame_generation_times:
                all_generation_times.extend(camera.frame_generation_times)
        
        if all_generation_times:
            return (sum(all_generation_times) / len(all_generation_times)) * 1000  # 转换为毫秒
        return 0.0
    
    def _calculate_throughput(self) -> float:
        """计算吞吐量（帧/秒）"""
        if len(self.performance_snapshots) < 2:
            return 0.0
            
        recent_snapshots = self.performance_snapshots[-10:]  # 最近10个快照
        if len(recent_snapshots) < 2:
            return 0.0
            
        time_diff = (recent_snapshots[-1].timestamp - recent_snapshots[0].timestamp).total_seconds()
        if time_diff <= 0:
            return 0.0
            
        # 计算这段时间内的总帧数
        total_frames = 0
        for camera in self.cameras.values():
            if camera.is_active:
                total_frames += len(camera.frame_generation_times)
        
        return total_frames / time_diff
    
    async def run_ramp_up_test(self, target_cameras: int, ramp_up_time: int) -> Dict[str, Any]:
        """运行逐步增加负载测试"""
        logger.info(f"开始逐步增加负载测试: 目标 {target_cameras} 路摄像头，时间 {ramp_up_time} 秒")
        
        cameras_list = list(self.cameras.values())[:target_cameras]
        cameras_per_step = max(1, target_cameras // 10)  # 分10步增加
        step_interval = ramp_up_time / 10
        
        results = {
            "target_cameras": target_cameras,
            "ramp_up_time": ramp_up_time,
            "steps": [],
            "final_active_cameras": 0,
            "success_rate": 0.0
        }
        
        active_count = 0
        for step in range(10):
            step_start = step * cameras_per_step
            step_end = min((step + 1) * cameras_per_step, target_cameras)
            
            # 启动这一步的摄像头
            step_cameras = cameras_list[step_start:step_end]
            step_results = {"step": step + 1, "cameras_started": 0, "cameras_failed": 0}
            
            for camera in step_cameras:
                try:
                    await camera.start()
                    step_results["cameras_started"] += 1
                    active_count += 1
                except Exception as e:
                    logger.warning(f"摄像头 {camera.camera_id} 启动失败: {e}")
                    step_results["cameras_failed"] += 1
            
            results["steps"].append(step_results)
            
            logger.info(f"步骤 {step + 1}: 启动 {step_results['cameras_started']} 路摄像头，"
                       f"失败 {step_results['cameras_failed']} 路，总计活跃 {active_count} 路")
            
            # 等待下一步
            if step < 9:  # 最后一步不需要等待
                await asyncio.sleep(step_interval)
        
        results["final_active_cameras"] = active_count
        results["success_rate"] = active_count / target_cameras
        
        logger.info(f"逐步增加负载测试完成: 成功启动 {active_count}/{target_cameras} 路摄像头，"
                   f"成功率 {results['success_rate']:.2%}")
        
        return results
    
    async def run_stability_test(self, duration: int) -> Dict[str, Any]:
        """运行稳定性测试"""
        logger.info(f"开始稳定性测试，持续时间 {duration} 秒")
        
        start_time = datetime.now()
        end_time = start_time + timedelta(seconds=duration)
        
        # 记录初始状态
        initial_active = sum(1 for cam in self.cameras.values() if cam.is_active)
        
        results = {
            "duration": duration,
            "initial_active_cameras": initial_active,
            "stability_events": [],
            "final_active_cameras": 0,
            "uptime_percentage": 0.0,
            "error_events": 0
        }
        
        # 运行稳定性测试
        while datetime.now() < end_time:
            try:
                # 检查摄像头状态
                current_active = sum(1 for cam in self.cameras.values() if cam.is_active)
                
                # 模拟一些摄像头可能出现的问题
                if random.random() < 0.01:  # 1%概率出现问题
                    # 随机选择一个活跃的摄像头模拟故障
                    active_cameras = [cam for cam in self.cameras.values() if cam.is_active]
                    if active_cameras:
                        failed_camera = random.choice(active_cameras)
                        await failed_camera.stop()
                        
                        event = {
                            "timestamp": datetime.now().isoformat(),
                            "type": "camera_failure",
                            "camera_id": failed_camera.camera_id,
                            "active_cameras_before": current_active,
                            "active_cameras_after": current_active - 1
                        }
                        results["stability_events"].append(event)
                        results["error_events"] += 1
                        
                        logger.warning(f"摄像头 {failed_camera.camera_id} 模拟故障")
                        
                        # 模拟故障恢复
                        await asyncio.sleep(random.uniform(1, 5))  # 1-5秒后恢复
                        try:
                            await failed_camera.start()
                            recovery_event = {
                                "timestamp": datetime.now().isoformat(),
                                "type": "camera_recovery",
                                "camera_id": failed_camera.camera_id,
                                "recovery_time_seconds": 3.0
                            }
                            results["stability_events"].append(recovery_event)
                            logger.info(f"摄像头 {failed_camera.camera_id} 恢复正常")
                        except Exception as e:
                            logger.error(f"摄像头 {failed_camera.camera_id} 恢复失败: {e}")
                
                await asyncio.sleep(1)  # 每秒检查一次
                
            except Exception as e:
                logger.error(f"稳定性测试错误: {e}")
                await asyncio.sleep(1)
        
        # 计算最终结果
        final_active = sum(1 for cam in self.cameras.values() if cam.is_active)
        uptime_percentage = (final_active / max(1, initial_active)) * 100
        
        results["final_active_cameras"] = final_active
        results["uptime_percentage"] = uptime_percentage
        
        logger.info(f"稳定性测试完成: 初始 {initial_active} 路，最终 {final_active} 路，"
                   f"正常运行率 {uptime_percentage:.1f}%，错误事件 {results['error_events']} 次")
        
        return results
    
    def generate_test_report(self) -> Dict[str, Any]:
        """生成测试报告"""
        if not self.performance_snapshots:
            return {"error": "没有性能数据"}
        
        # 计算统计指标
        cpu_values = [s.cpu_percent for s in self.performance_snapshots]
        memory_values = [s.memory_percent for s in self.performance_snapshots]
        gpu_values = [s.gpu_utilization for s in self.performance_snapshots]
        error_rates = [s.error_rate for s in self.performance_snapshots]
        latencies = [s.latency_ms for s in self.performance_snapshots]
        
        # 摄像头统计
        camera_stats = []
        for camera in self.cameras.values():
            camera_stats.append(camera.get_statistics())
        
        report = {
            "test_summary": {
                "total_cameras": len(self.cameras),
                "test_duration_seconds": len(self.performance_snapshots) * 5,  # 每5秒一个快照
                "total_snapshots": len(self.performance_snapshots)
            },
            "performance_statistics": {
                "cpu_usage": {
                    "min": min(cpu_values),
                    "max": max(cpu_values),
                    "avg": sum(cpu_values) / len(cpu_values),
                    "exceeded_threshold": sum(1 for v in cpu_values if v > self.config.cpu_threshold)
                },
                "memory_usage": {
                    "min": min(memory_values),
                    "max": max(memory_values),
                    "avg": sum(memory_values) / len(memory_values),
                    "exceeded_threshold": sum(1 for v in memory_values if v > self.config.memory_threshold)
                },
                "gpu_usage": {
                    "min": min(gpu_values),
                    "max": max(gpu_values),
                    "avg": sum(gpu_values) / len(gpu_values),
                    "exceeded_threshold": sum(1 for v in gpu_values if v > self.config.gpu_threshold)
                },
                "error_rate": {
                    "min": min(error_rates),
                    "max": max(error_rates),
                    "avg": sum(error_rates) / len(error_rates),
                    "exceeded_threshold": sum(1 for v in error_rates if v > self.config.error_threshold)
                },
                "latency_ms": {
                    "min": min(latencies),
                    "max": max(latencies),
                    "avg": sum(latencies) / len(latencies)
                }
            },
            "camera_statistics": camera_stats,
            "recommendations": self._generate_recommendations()
        }
        
        return report
    
    def _generate_recommendations(self) -> List[str]:
        """生成优化建议"""
        recommendations = []
        
        if not self.performance_snapshots:
            return ["无法生成建议：缺少性能数据"]
        
        # 分析CPU使用率
        cpu_values = [s.cpu_percent for s in self.performance_snapshots]
        avg_cpu = sum(cpu_values) / len(cpu_values)
        if avg_cpu > self.config.cpu_threshold:
            recommendations.append(f"CPU使用率过高（平均{avg_cpu:.1f}%），建议增加处理节点或优化算法")
        
        # 分析内存使用率
        memory_values = [s.memory_percent for s in self.performance_snapshots]
        avg_memory = sum(memory_values) / len(memory_values)
        if avg_memory > self.config.memory_threshold:
            recommendations.append(f"内存使用率过高（平均{avg_memory:.1f}%），建议增加内存或优化缓存策略")
        
        # 分析错误率
        error_rates = [s.error_rate for s in self.performance_snapshots]
        avg_error_rate = sum(error_rates) / len(error_rates)
        if avg_error_rate > self.config.error_threshold:
            recommendations.append(f"错误率过高（平均{avg_error_rate:.3f}），建议检查网络连接和摄像头状态")
        
        # 分析摄像头性能
        total_cameras = len(self.cameras)
        active_cameras = sum(1 for cam in self.cameras.values() if cam.is_active)
        if active_cameras / total_cameras < 0.9:
            recommendations.append(f"摄像头活跃率较低（{active_cameras}/{total_cameras}），建议检查摄像头连接")
        
        if not recommendations:
            recommendations.append("系统性能良好，无需特别优化")
        
        return recommendations
    
    async def cleanup(self):
        """清理资源"""
        logger.info("开始清理测试资源")
        
        # 停止性能监控
        await self.stop_performance_monitoring()
        
        # 停止所有摄像头
        for camera in self.cameras.values():
            if camera.is_active:
                await camera.stop()
        
        logger.info("测试资源清理完成")


class TestReportGenerator:
    """测试报告生成器"""
    
    @staticmethod
    def save_report_to_file(report: Dict[str, Any], filename: str):
        """保存报告到文件"""
        try:
            with open(filename, 'w', encoding='utf-8') as f:
                json.dump(report, f, ensure_ascii=False, indent=2, default=str)
            logger.info(f"测试报告已保存到: {filename}")
        except Exception as e:
            logger.error(f"保存测试报告失败: {e}")
    
    @staticmethod
    def print_summary_report(report: Dict[str, Any]):
        """打印摘要报告"""
        print("\n" + "="*60)
        print("负载测试报告摘要")
        print("="*60)
        
        if "test_summary" in report:
            summary = report["test_summary"]
            print(f"总摄像头数: {summary['total_cameras']}")
            print(f"测试时长: {summary['test_duration_seconds']} 秒")
            print(f"性能快照数: {summary['total_snapshots']}")
        
        if "performance_statistics" in report:
            perf = report["performance_statistics"]
            print(f"\nCPU使用率: 平均 {perf['cpu_usage']['avg']:.1f}%, "
                  f"最高 {perf['cpu_usage']['max']:.1f}%")
            print(f"内存使用率: 平均 {perf['memory_usage']['avg']:.1f}%, "
                  f"最高 {perf['memory_usage']['max']:.1f}%")
            print(f"GPU使用率: 平均 {perf['gpu_usage']['avg']:.1f}%, "
                  f"最高 {perf['gpu_usage']['max']:.1f}%")
            print(f"错误率: 平均 {perf['error_rate']['avg']:.3f}, "
                  f"最高 {perf['error_rate']['max']:.3f}")
            print(f"延迟: 平均 {perf['latency_ms']['avg']:.2f}ms, "
                  f"最高 {perf['latency_ms']['max']:.2f}ms")
        
        if "recommendations" in report:
            print(f"\n优化建议:")
            for i, rec in enumerate(report["recommendations"], 1):
                print(f"  {i}. {rec}")
        
        print("="*60)